
#ifndef __ENGINE_H__
#define __ENGINE_H__

#include <d3d9.h>
#include <d3d9types.h>
#include <d3dx9core.h>
#include <strsafe.h>
#include <vector>
#include <string>
#include "Color.h"
#include "Real3.h"
#include "RenderState.h"
#include "Player.h"

using namespace std;

class Entity;
class Camera;
class TerrainGeom;
struct D3DXMATRIX; 

struct Message
{
	Message(const string &_text, float _time = 5.0f)
	{
		text = _text;
		time = _time;
	}

	string text;
	float time;
};

class Engine
{
public:

	// Contructor / Destructor
	Engine();
	~Engine();

	// Initialization
	bool Initialize(HWND _window);

	// Main controlling methods
	void MainLoop();

	// Rendering Methods
	void BeginRender();
	void EndRender();

	// Load Matrices
	void LoadMatrices(D3DXMATRIX *worldMatrix); 

	// Sets the lights
	void SetupLights();

	// Load lights
	void LoadLights();

	// Draws text to the screen
	void DrawStringSmall(short x, short y, LPCWSTR str, Color c = __white);
	void DrawStringLarge(short x, short y, LPCWSTR str, Color c = __white);

	// Reads a vector of strings and tries to do what they say
	bool RunScript(const vector<string> &toks);

	// Writes out all the data to a file
	void SaveScene(string fileName, bool inBinary);
	void SaveSceneTree(string dirName, bool inBinary);

	// Loads from a file
	void LoadScene(string fileName);
	Entity *LoadEntity(string fileName, bool inBinary);
	Entity *LoadHeightMap(string fileName);

	// Returns renderFlag
	uchar RenderFlag() const { return renderFlag; }

	// Renders Billboards
	void RenderBillboards();

	// Adds vertices & faces
	void AddVertices(uint v) { rVertices += v; }
	void AddFaces(uint f)    { rFaces += f; }

	// Global scene entity
	Entity *scene;

	// Camera for viewing
	Camera *camera;

	// Terrain
	TerrainGeom *terrain;

	// Player
	Player player;

	// Gravity level
	float gravity;

	// Time of last rendered frame
	DWORD lastTime;

	// Time spent in last rendered frame
	float lastFrameLength; 
	
	// D3D Variables
	LPDIRECT3D9				direct3DInterface; 
	LPDIRECT3DDEVICE9 direct3DRenderer; 

	// Collision test on the entire scene
	bool CollisionTest(Entity *entity);

	// Sockets stuff
	void CreateServer();
	void JoinServer(const string &ip);

	// Messages on the screen
	vector<Message> messages;

	// Microsoft Windows window
	HWND *window;

private:

	// Font Device
	ID3DXFont *fontS; 
	ID3DXFont *fontL; 

	// Flags
	bool isRendering : 1;
	bool renderWireframe : 1;
	bool renderPoints : 1;
	bool renderNormals : 1;
	bool renderBBoxes : 1;
	bool lighting : 1;
	uchar renderFlag : 2;

	// Level of Detail -- 0 == low, 1 == med, 2 == high
	//TODO: make an enum or something
	uchar lod;

	// Currently rendering state
	RenderState *state;

	// Lights
	D3DLIGHT9 light; 

	// Number of things rendered this frame
	uint rVertices;
	uint rFaces;

	// Initialize Methods
	bool InitEngine();
	bool InitStates();
	bool InitFonts();

	// Render Method
	void Render();
	void RenderNormals();
	void RenderBBoxes();

	// BBox buffers
	void BuildBBoxIndexBuffer();
	LPDIRECT3DINDEXBUFFER9 boxIndexBuffer;
	
	// Loading variables
	float lPercent;
	string lText;

	// Switches the buffers
	void SwitchBuffers();

	// Draws the engine stats
	void DrawStats();

	// Processes the keys
	void ProcessKeys();

	// Draws and handles a command line
	bool commandActive;
	string commandLine;
	void CommandWindow();
	void DrawMessages();

	// Writes the current settings to disk
	bool WriteSettings(const char* filename="..\\bin\\settings.ini");

	// Allows access to private variables
	friend class STATE(MainMenu);
	friend class STATE(CreateGame);
	friend class STATE(JoinGame);
	friend class STATE(Settings);
	friend class STATE(_3D);
	friend class STATE(Loading);
};

extern Engine engine;

#endif // __ENGINE_H__